package com.zijidelu.luframework.utils.lang.function;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;

/**
 * 简洁高效的Lambda表达式工具类
 * 专注于核心功能，避免过度复杂化
 *
 * @author ZIJIDELU
 */
public class LambdaUtil {

    // ==================== 字段名提取方法 ====================

    /**
     * 通过getter方法引用获取字段名
     */
    public static <T, R> String getFieldName(SFunction<T, R> getter) {
        return extractFieldName(getter);
    }

    /**
     * 通过setter方法引用获取字段名
     */
    public static <T, R> String getFieldName(SBiConsumer<T, R> setter) {
        return extractFieldName(setter);
    }

    // ==================== 类信息提取方法 ====================

    /**
     * 获取实体类（高性能，避免Class.forName()）
     */
    public static <T, R> Class<?> getEntityClass(SFunction<T, R> getter) {
        String className = extractEntityClassName(getter);
        return loadClassOptimized(className);
    }

    public static <T, R> Class<?> getEntityClass(SBiConsumer<T, R> setter) {
        String className = extractEntityClassName(setter);
        return loadClassOptimized(className);
    }

    /**
     * 获取实体类名（仅字符串操作，最高性能）
     */
    public static <T, R> String getEntityClassName(SFunction<T, R> getter) {
        return extractEntityClassName(getter);
    }

    public static <T, R> String getEntityClassName(SBiConsumer<T, R> setter) {
        return extractEntityClassName(setter);
    }

    /**
     * 获取方法名
     */
    public static <T, R> String getMethodName(SFunction<T, R> getter) {
        return extractMethodName(getter);
    }

    public static <T, R> String getMethodName(SBiConsumer<T, R> setter) {
        return extractMethodName(setter);
    }

    // ==================== 核心实现 ====================

    /**
     * 提取字段名的核心方法
     */
    private static String extractFieldName(Object lambda) {
        if (lambda == null) {
            throw new IllegalArgumentException("Lambda表达式不能为null");
        }

        try {
            Method writeReplaceMethod = lambda.getClass().getDeclaredMethod("writeReplace");
            writeReplaceMethod.setAccessible(true);
            SerializedLambda serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(lambda);
            String methodName = serializedLambda.getImplMethodName();
            return convertMethodNameToFieldName(methodName);

        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("无法提取字段名：Lambda表达式必须是方法引用（如 User::getName），不能是lambda表达式", e);
        } catch (Exception e) {
            throw new RuntimeException("提取字段名时发生错误: " + e.getMessage(), e);
        }
    }

    /**
     * 提取实体类名的核心方法
     */
    private static String extractEntityClassName(Object lambda) {
        if (lambda == null) {
            throw new IllegalArgumentException("Lambda表达式不能为null");
        }

        try {
            Method writeReplaceMethod = lambda.getClass().getDeclaredMethod("writeReplace");
            writeReplaceMethod.setAccessible(true);
            SerializedLambda serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(lambda);
            String internalClassName = serializedLambda.getImplClass();
            return internalClassName.replace('/', '.');

        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("无法提取类名：Lambda表达式必须是方法引用（如 User::getName），不能是lambda表达式", e);
        } catch (Exception e) {
            throw new RuntimeException("提取类名时发生错误: " + e.getMessage(), e);
        }
    }

    /**
     * 提取方法名的核心方法
     */
    private static String extractMethodName(Object lambda) {
        if (lambda == null) {
            throw new IllegalArgumentException("Lambda表达式不能为null");
        }

        try {
            Method writeReplaceMethod = lambda.getClass().getDeclaredMethod("writeReplace");
            writeReplaceMethod.setAccessible(true);
            SerializedLambda serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(lambda);
            return serializedLambda.getImplMethodName();

        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("无法提取方法名：Lambda表达式必须是方法引用（如 User::getName），不能是lambda表达式", e);
        } catch (Exception e) {
            throw new RuntimeException("提取方法名时发生错误: " + e.getMessage(), e);
        }
    }

    /**
     * 优化的类加载方法，避免Class.forName()的性能问题
     */
    private static Class<?> loadClassOptimized(String className) {
        try {
            // 优先使用当前类的ClassLoader，性能最佳
            ClassLoader classLoader = LambdaUtil.class.getClassLoader();
            if (classLoader != null) {
                return classLoader.loadClass(className);
            }

            // 回退到线程上下文ClassLoader
            classLoader = Thread.currentThread().getContextClassLoader();
            if (classLoader != null) {
                return classLoader.loadClass(className);
            }

            // 最后使用Class.forName()
            return Class.forName(className);

        } catch (ClassNotFoundException e) {
            throw new RuntimeException("无法找到类: " + className, e);
        }
    }

    /**
     * 将方法名转换为字段名
     */
    private static String convertMethodNameToFieldName(String methodName) {
        if (methodName == null || methodName.isEmpty()) {
            throw new IllegalArgumentException("方法名不能为空");
        }

        if (methodName.startsWith("get")) {
            if (methodName.length() > 3) {
                return methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
            } else {
                throw new IllegalArgumentException("无效的getter方法名: " + methodName);
            }
        } else if (methodName.startsWith("set")) {
            if (methodName.length() > 3) {
                return methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
            } else {
                throw new IllegalArgumentException("无效的setter方法名: " + methodName);
            }
        } else if (methodName.startsWith("is")) {
            if (methodName.length() > 2) {
                return methodName.substring(2, 3).toLowerCase() + methodName.substring(3);
            } else {
                throw new IllegalArgumentException("无效的is方法名: " + methodName);
            }
        } else {
            return methodName;
        }
    }
}
